package com.zk.config.web.controller;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.KeeperException.NoAuthException;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.google.gson.Gson;
import com.zk.config.api.util.ZkCom;
import com.zk.config.web.constants.Constants;
import com.zk.config.web.model.FileInfo;
import com.zk.config.web.model.Response;
import com.zk.config.web.model.TreeData;
import com.zk.config.web.model.ZkData;
import com.zk.config.web.model.ZkPerms;
import com.zk.config.web.op.MyZkClient;
import com.zk.config.web.op.Zk;
import com.zk.config.web.util.ComUtil;
import com.zk.config.web.util.Permiss;
import com.zk.config.web.util.ZkCacheUtil;

import lombok.Setter;

@Controller
@RequestMapping("/read")
public class ZkReadController {
	private static final Logger log = LoggerFactory.getLogger(ZkReadController.class);
	@Setter
	@Value("${zookeeper.backup.directory}")
	private String backupDirPath;
	
//	@Value("${user}")
//	private String user;
//	@Value("${userName}")
//	private String userName;
//	@Resource
//	private Properties configProperties;
//	@Resource
//	private Test test;
	
	private Gson gson = new Gson();
	@RequestMapping("/addr")
	public String addr(HttpServletRequest request, RedirectAttributes attr, Model model, @RequestParam(required = true) String cxnstr, @RequestParam(required = false) String path) {
		if (StringUtils.isBlank(cxnstr)) {
			return "redirect:/";
		}
//		// 这里是测试注入的代码
//		System.out.println("############################user="+ user + ",userName=" + userName);
//		// 这里是测试注入的动态变化的值的代码
//		System.out.println("#######configProperties######user="+configProperties.getProperty("user") + ",userName=" + configProperties.getProperty("userName"));
//		test.init();
		
		HttpSession session = request.getSession();
		session.setAttribute(Constants.CX_STR, cxnstr);
		attr.addFlashAttribute(Constants.CX_STR, StringUtils.trimToEmpty(cxnstr));
		Zk reader = new Zk(cxnstr);
		String realPath = StringUtils.trimToEmpty(path);
		if(reader != null && StringUtils.isNotEmpty(realPath)) {
			realPath = ComUtil.getRealPath((MyZkClient)reader.getClient(), realPath);
		}
		model.addAttribute("zkpath", realPath);
		BaseMsg baseMsg = (BaseMsg)session.getAttribute("baseMsg");
		if (baseMsg == null) {
			baseMsg = new BaseMsg();
		} else {
			session.removeAttribute("baseMsg");
		}
		File fileDir = new File(backupDirPath);
		List<FileInfo> fileList = new ArrayList<>();
		if (fileDir != null && fileDir.exists()) {
			File[] files = fileDir.listFiles();
			if (files != null && files.length > 0) {
				for(File file:files) {
					FileInfo fInfo = new FileInfo();
					String fileName = file.getName();
					fInfo.setName(fileName);
					fInfo.setSize(file.length());
					long time = file.lastModified();
					fInfo.setTime(new Date(time));
					fInfo.setTimeLong(time);
					fileList.add(fInfo);
				}
				Collections.sort(fileList, new Comparator<FileInfo>() {
					@Override
					public int compare(FileInfo a, FileInfo b) {
						if (a == null) return -1;
						if (b == null) return 1;
						if(a.getTimeLong() == b.getTimeLong()) return 0;
						return a.getTimeLong() < b.getTimeLong()?1:-1;
					}
		        });
			}
		} else {
			if (!fileDir.mkdirs()) {
				baseMsg.addErrMsg("备份目录不存在，创建失败，请检查备份目录是否正确！");
			}
		}
		model.addAttribute("fileList", fileList);
		model.addAttribute("baseMsg", baseMsg);
		return "node";
	}
	
	@RequestMapping("/node")
	public void node(HttpServletRequest request, HttpServletResponse response) {
		HttpSession session = request.getSession();
		String cxnstr = (String) session.getAttribute(Constants.CX_STR);
		String path = request.getParameter("path");
		path = ZkCom.getZkPath(path);
		response.setContentType("application/json;charset=UTF-8");
		if (StringUtils.isBlank(cxnstr)) {
			try {
				response.getWriter().print("");
			} catch (IOException e) {
				e.printStackTrace();
			}
			return;
		}
		Zk reader = new Zk(cxnstr);
		TreeData td = ZkCacheUtil.setNodeCache((MyZkClient)reader.getClient(), path);
		List<TreeData> srcZkNodes = new ArrayList<>();
		if(td != null) {
			srcZkNodes.add(td);
		}
		List<TreeData> zkNodes = new ArrayList<>();
		ComUtil.getZkNodes(zkNodes, srcZkNodes, "/", path);
		try {
			response.getWriter().print(gson.toJson(zkNodes));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	@RequestMapping("/getData")
	public String getData(HttpServletRequest request, Model model, String path) {
		HttpSession session = request.getSession();
		String cxnstr = (String) session.getAttribute(Constants.CX_STR);
		if (StringUtils.isBlank(cxnstr)) {
			return "redirect:/";
		}
		path = ZkCom.getZkPath(path);
		model.addAttribute("zkpath", path);
		model.addAttribute("pathList", Arrays.asList(StringUtils.split(path, "/")));

		TreeData treeData = null;
		Zk reader = new Zk(cxnstr);
		MyZkClient client = (MyZkClient)reader.getClient();
		if(client.useCache && client.saveNodeDataToCache) {
			treeData = client.zkData.get(path);
		}

		ZkData zkData = null;
		List<ZkPerms> noAuthPerms = null;
		if(treeData != null && treeData.getData() != null) {
			zkData = treeData.getData();
		} else {
			try {
				zkData = reader.readData(path);
			} catch (Exception e) {
				log.error(e.getMessage());
				if(e.getCause() instanceof NoAuthException) {
					noAuthPerms = Permiss.getPerms(client.getZooKeeper(), path);
				}
			}
			if(client.useCache && client.saveNodeDataToCache) {
				if(treeData != null) {
					treeData.setData(zkData);
				}
			}
		}		
		
		if (zkData != null) {
			model.addAttribute("data", zkData.getDataString());
			model.addAttribute("dataSize", zkData.getData() != null?zkData.getData().length:0);
			try {
				Map<String, Object> statMap = PropertyUtils.describe(zkData.getStat());
				if(statMap.containsKey("ctime")) {
					statMap.put("ctime", new Date(Long.parseLong(String.valueOf(statMap.get("ctime")))));
				}
				if(statMap.containsKey("mtime")) {
					statMap.put("mtime", new Date(Long.parseLong(String.valueOf(statMap.get("mtime")))));
				}
				statMap.remove("class");
				model.addAttribute("stat", statMap);
			} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
				log.error(e.getMessage(), e);
			}
		} else if(noAuthPerms != null){
			Gson gson = new Gson();
			Map<String, Object> statMap = new HashMap<>();
			statMap.put("没有权限，用户权限为：", gson.toJson(noAuthPerms));
			model.addAttribute("stat", statMap);
		}

		return "right";
	}
	
	@RequestMapping("/closeCache")
	public void closeCache(HttpServletRequest request, HttpServletResponse response) {
		Response res = new Response();
		int state = -1;
		HttpSession session = request.getSession();
		String cxnstr = (String) session.getAttribute(Constants.CX_STR);
		if (StringUtils.isBlank(cxnstr)) {
			res.setState(state);
			res.setMsg("登录超时！");
			ComUtil.writeResponse(response, res);
			return;
		}
		Zk reader = new Zk(cxnstr);
		MyZkClient client = (MyZkClient)reader.getClient();
		client.useCache = false;
		client.zkData.clear();
		response.setContentType("application/json;charset=UTF-8");
		try {
			response.getWriter().print(gson.toJson(res));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	@RequestMapping("/openCache")
	public void openCache(HttpServletRequest request, HttpServletResponse response) {
		HttpSession session = request.getSession();
		String cxnstr = (String) session.getAttribute(Constants.CX_STR);
		Response res = new Response();
		int state = -1;
		if (StringUtils.isBlank(cxnstr)) {
			res.setState(state);
			res.setMsg("登录超时！");
			ComUtil.writeResponse(response, res);
			return;
		}
		Zk reader = new Zk(cxnstr);
		MyZkClient client = (MyZkClient)reader.getClient();
		client.useCache = true;
		client.zkData.clear();
		ZkCacheUtil.setNodeCache(client, null);
		response.setContentType("application/json;charset=UTF-8");
		try {
			response.getWriter().print(gson.toJson(res));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
